﻿using HtmlAgilityPack;
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using WxBean.Core.Common;
using WxBean.Core.Common.Helper;
using WxBean.Core.Model;
using WxBean.Core.Model.Enum;
using WxBean.Core.Services.BASE;

namespace WxBean.Core.Services
{
    public class GuFengComic : IComic
    {

        private WebBasic _webBasic { get; set; }
        public async Task<IEnumerable<ComicModelDto>> ExecuteAsync(WebBasic webBasic, string name)
        {
            var currentTask = new ConcurrentTask(10);
            var taskList = new List<Task>();
            var comicList = new List<ComicModelDto>();
            try
            {
                _webBasic = webBasic;
                var fullPath = webBasic.Url.ToString() + webBasic.Param + name;

                var doc = await GetHtmlDocumentAsync(fullPath);

                var nodeList = doc.DocumentNode.SelectNodes("//li[@class='item-lg']");

                foreach (var node in nodeList)
                {
                    var task = GetComicInfoAsync(webBasic, comicList, node);
                    taskList.Add(task);
                }

                await Task.WhenAll(taskList);
            }
            catch (Exception ex)
            {
                await Console.Out.WriteLineAsync($"开始处理漫画信息:{ex.Message}");
                throw;
            }


            return comicList;
        }

        /// <summary>
        /// 获取漫画信息
        /// </summary>
        /// <param name="webBasic"></param>
        /// <param name="comicList"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        private async Task GetComicInfoAsync(WebBasic webBasic, List<ComicModelDto> comicList, HtmlNode node)
        {
            var comic = new ComicModelDto();
            var aTag = node.SelectSingleNode("./a");
            var url = aTag.Attributes["href"]?.Value;
            var title = node.SelectSingleNode("./a").Attributes["title"]?.Value;
            var converUrl = node.SelectSingleNode("./a/img").Attributes["src"]?.Value;
            var updateTo = node.SelectSingleNode("./a/span[@class='tt']").InnerText;

            comic.LastUpdate = updateTo;
            comic.CoverUrl = converUrl;
            comic.Source = webBasic.Name;
            comic.CreateTime = DateTime.Now;
            comic.UpdateTime = DateTime.Now;
            comic.Url = url;
            comic.Name = title;
            comic.UId = Guid.NewGuid().ToString();

            ///处理漫画详情
            await GetComicDetailAsync(comic);

            comicList.Add(comic);
        }

        /// <summary>
        /// 获取漫画详情内容
        /// </summary>
        /// <param name="comic"></param>
        /// <returns></returns>
        public async Task<ComicModelDto> GetComicDetailAsync(ComicModelDto comic)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(comic.Url))
                {
                    return comic;
                }

                var doc = await GetHtmlDocumentAsync(comic.Url);

                var nodes = doc.DocumentNode.SelectNodes("//*[contains(concat(' ', normalize-space(@class), ' '), ' book-cont cf ')]//div");

                foreach (var item in nodes)
                {
                    var imgDom = item.SelectSingleNode(".//img");
                    var lastUpdate = item.SelectSingleNode(".//span[@class='text ']");
                    var detailDoms = item.SelectNodes(".//ul[@class='detail-list cf']/li");

                    if (imgDom != null)
                    {
                        comic.CoverUrl = imgDom.Attributes["src"]?.Value;
                    }
                    if (lastUpdate != null)
                    {
                        comic.LastUpdate = lastUpdate.InnerText;

                    }

                    if (detailDoms != null && detailDoms.Count > 0)
                    {
                        var status = detailDoms[0]?.SelectSingleNode("./span/a")?.InnerText ?? "";
                        comic.Status = DetermineStatus(status);
                        comic.Author = detailDoms[1]?.SelectNodes("./span/a")?[1]?.InnerText ?? "";
                        var lastUpdateTime = detailDoms[2]?.SelectNodes("./span")?[0]?.InnerText ?? "";

                        comic.LastUpdateTime = ConvertLastUpdateTime(lastUpdateTime);
                        break;
                    }
                }
                var str = GetComicLastUpdateName(comic.LastUpdate);
                comic.LastNumber = str.Item1;
                comic.LastChapterName = str.Item2;
                // 去获取漫画的每一章节内容
                await GetChapterListAsync(comic);
            }
            catch (Exception ex)
            {
                await Console.Out.WriteLineAsync($"获取漫画详细信息:{ex.Message}");
                throw;
            }

            return comic;
        }


        /// <summary>
        /// 判断当前漫画是什么状态
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>

        public ComicStatus DetermineStatus(string status)
        {
            if (string.IsNullOrEmpty(status))
            {
                return ComicStatus.UnKnow;
            }

            switch (status)
            {
                case "连载中":
                    return ComicStatus.Serializing;
                case "已完结":
                    return ComicStatus.Completed;
                default:
                    return ComicStatus.UnKnow;
            }
        }

        /// <summary>
        /// 获取网址的html节点
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public async Task<HtmlDocument> GetHtmlDocumentAsync(string path)
        {
            var html_str = await HttpHelper.GetAsync(path);
            var doc = new HtmlDocument();
            doc.LoadHtml(html_str);
            return doc;
        }

        /// <summary>
        /// 获取漫画对应章节
        /// </summary>
        /// <returns></returns>
        public async Task GetChapterListAsync(ComicModelDto comic)
        {
            var doc = await GetHtmlDocumentAsync(comic.Url);
            ThreadPool.SetMinThreads(1500, 1500);
            var nodeList = doc.DocumentNode.SelectNodes(".//ul[@id='chapter-list-1']/li");
            comic.ChpterList = new List<ComicChapterDto>();
            var taskList = new List<Task>();
            var chapterNum = 1;
            try
            {
                foreach (var item in nodeList)
                {
                    var url = item.SelectSingleNode("./a")?.Attributes["href"]?.Value;
                    var name = item.SelectSingleNode("./a/span")?.InnerText;
                    if (string.IsNullOrEmpty(url))
                    {
                        continue;
                    }
                    var result = GetComicLastUpdateName(name);

                    var chpter = new ComicChapterDto
                    {
                        ComicUId = comic.UId,
                        ChapterDetailUId = Guid.NewGuid().ToString(),
                        Url = GetHttpsUrl(url),
                        Name = result.Item2 ?? "",
                        Number = result.Item1 ?? chapterNum.ToString(),
                        UpdateTime = DateTime.Now,
                        CreateTime = DateTime.Now,

                    };
                    chapterNum += 1;
                    comic.ChpterList.Add(chpter);
                }

                ConcurrentTask concurrentTask = new ConcurrentTask(comic.ChpterList.Count);

                foreach (var item in comic.ChpterList)
                {
                    await concurrentTask.RunAsync(async () => await ChpterDetailRunAsync(item));
                }

                await concurrentTask.WaitTaskCompltedAsync("获取漫画对应章节");
            }
            catch (Exception ex)
            {
                await Console.Out.WriteLineAsync($"获取漫画对应章节:{ex.Message}");
            }

        }

        private async Task ChpterDetailRunAsync(ComicChapterDto item)
        {
            try
            {
                var html_str = StringHelper.ToReplace((await HttpHelper.GetAsync(item.Url)), " ", string.Empty);

                var scripts = Regex.Matches(html_str, "<script>;(.*?);</script><divclass=\"chapter-view\">");
                foreach (Match item2 in scripts)
                {
                    item.ChapterDetailList = new List<ComicChapterDetailDto>();

                    if (item2.Groups == null)
                    {
                        continue;
                    }
                    var goup = item2.Groups[1]?.Value;

                    var siteUrlStr = Regex.Match(goup, "varsiteUrl=\".*?\"")?.Value ?? "";
                    var chapterPath = Regex.Match(goup, "varchapterPath=\".*?\"")?.Value ?? "";
                    var chapterImages = Regex.Match(goup, RegexConstant.GetBracketed)?.Value ?? "";
                    var pageImage = Regex.Match(goup, "pageImage=\".*?\"")?.Value ?? "";
                    var title = Regex.Match(goup, "pageTitle=\".*?\"")?.Value ?? "";

                    if (!chapterImages?.Any() ?? true)
                    {
                        continue;
                    }
                    var images = JsonConvert.DeserializeObject<List<string>>(chapterImages);

                    for (int i = 0; i < images.Count(); i++)
                    {
                        var item3 = images[i];
                        var model = new ComicChapterDetailDto
                        {
                            Number = (i + 1).ToString(),
                            Uid = item.ChapterDetailUId,
                            SiteUrl = StringHelper.ToReplace(GetMatche(RegexConstant.GetComicInfo, siteUrlStr), "\"", string.Empty) ?? "",
                            ChapterPath = StringHelper.ToReplace(GetMatche(RegexConstant.GetComicInfo, chapterPath), "\"", string.Empty) ?? "",
                            PageImage = StringHelper.ToReplace(GetMatche(RegexConstant.GetComicInfo, pageImage), "\"", string.Empty) ?? "",
                            ComicUrl = StringHelper.ToReplace(GetMatche(RegexConstant.GetComicInfo, pageImage), "\"", string.Empty) ?? "",
                            Title = StringHelper.ToReplace(GetMatche(RegexConstant.GetComicInfo, title), "\"", string.Empty) ?? "",
                        };
                        model.ComicUrl = model.ComicUrl.Substring(0, model.ComicUrl.IndexOf(".com") + 4);
                        model.Url = Path.Combine(model.ComicUrl, model.ChapterPath, item3);
                        //await Console.Out.WriteLineAsync(model.Number + "-" + model.Title);
                        item.ChapterDetailList.Add(model);

                    }
                }
            }
            catch (Exception ex)
            {
                await Console.Out.WriteLineAsync($"获取漫画详情方法：{ex.Message}");
                throw;
            }

        }

        /// <summary>
        /// 【正则】获取正则多个匹配结果
        /// </summary>
        /// <param name="regex"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public MatchCollection GetMatches(Regex regex, string input)
        {
            MatchCollection matches = regex.Matches(input);
            return matches;
        }

        /// <summary>
        /// 【正则】获取正则单个匹配结果
        /// </summary>
        /// <param name="regex"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public string GetMatche(Regex regex, string input)
        {
            Match matches = regex.Match(input);
            return matches?.Value ?? "";
        }



        /// <summary>
        /// 转换成最新更新时间
        /// </summary>
        /// <param name="lastUpdatetime"></param>
        /// <returns></returns>
        public DateTime ConvertLastUpdateTime(string lastUpdatetime)
        {
            if (string.IsNullOrEmpty(lastUpdatetime))
            {
                return DateTime.MinValue;
            }
            var lastTimeStr = lastUpdatetime.Split("：");
            var lastTime = DateTime.MinValue;
            if (lastTimeStr.Count() >= 1)
            {
                lastTime = DateTime.Parse(lastTimeStr[1]);
            }

            return lastTime;
        }

        /// <summary>
        /// 获取最新的章节 和章节名称
        /// </summary>
        /// <param name="lastUpdateTo"></param>
        /// <returns></returns>
        public (string, string) GetComicLastUpdateName(string lastUpdateTo)
        {
            if (!IsExistNumber(lastUpdateTo))
            {
                return (null, lastUpdateTo);
            }
            var name = string.Empty;
            var number = string.Empty;
            var strList = lastUpdateTo.Split(" ");
            if (strList?.Any() ?? true)
            {
                name = strList.Last();
                number = GetStrConverNum(strList[0]);
            }
            return (number, name);
        }

        /// <summary>
        /// 是否存在数字
        /// </summary>
        /// <param name="lastUpdateTo"></param>
        /// <returns></returns>
        public bool IsExistNumber(string lastUpdateTo)
        {
            if (string.IsNullOrEmpty(lastUpdateTo))
            {
                return false;
            }

            // 判断字符串中是否存在数字
            var hasNumber = Regex.IsMatch(lastUpdateTo, @"\d+");
            if (!hasNumber)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 获取字符串中的数字
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public string GetStrConverNum(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return "";
            }

            MatchCollection matches = Regex.Matches(str, @"\d+");
            if (matches?.Any() ?? true)
            {
                foreach (Match item in matches)
                {
                    int.TryParse(item.Value, out int value);
                    return value.ToString();
                }
            }
            return "";
        }

        /// <summary>
        /// 判断url 是否是https开头不是就拼接
        /// </summary>
        /// <param name="BaseUrl"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        public string GetHttpsUrl(string url)
        {
            if (string.IsNullOrWhiteSpace(url))
            {
                return "";
            }
            if (url.StartsWith("https:\\") || url.StartsWith("http:\\"))
            {
                return url;
            }
            return _webBasic.Url + url;
        }
    }
}
